/*
 * Email Notify
 * Author: Antonio Nastasi
 * Email: sifcenter (at) gmail.it
 * Version: 0.2
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include <QStringList>
#include "EmailChecker.h"


EmailChecker::EmailChecker()
{   
    connect(this, SIGNAL(finished()), this, SLOT(threadFinished()));
}

void EmailChecker::threadFinished()
{
    qDebug() << "Finish thread";
    closeConnection();    
}

EmailChecker::~EmailChecker()
{
    
}

void EmailChecker::run()
{
    connect(&socket, SIGNAL(encrypted()), this, SLOT(socketEncrypted()));
    connect(&socket, SIGNAL(connected()), this, SLOT(socketConnected()));
    connect(&socket, SIGNAL(readyRead()), this, SLOT(getMessage()));
    connect(&socket, SIGNAL(error(QAbstractSocket::SocketError )),this,SLOT(errorConnection(QAbstractSocket::SocketError )));
    state = NO_CONNECTED;
    currentEmails = -1;
    exec();
}

inline void EmailChecker::closeConnection()
{
    socket.close();
    state = NO_CONNECTED;
}

void EmailChecker::checkEmails()
{
    if( state >= CONNECTED){
	qDebug() << "Socket already connected";
	return;
    }
    if(server.isEmpty() || port ==0 ){	
	updateText("Configure me please!");
	return;
    }
    qDebug() << "server:" << server;
    qDebug() << "port:" << port;
    qDebug() << "ssl:" << ssl;
    qDebug() << "protocol:" << protocol;
    if(ssl)
	socket.connectToHostEncrypted(server,port);
    else
	socket.connectToHost(server,port);
    
    if(socket.waitForConnected(6000)){  
	qDebug() << "wait for connection: TRUE";	
    }
    else { 
	qDebug() << "wait for connection: FALSE";	
	closeConnection();	
	updateText("Connection Error");	
    }    
}

void EmailChecker::socketEncrypted()
{           
    qDebug() << "MODE:" << socket.mode();    
    state = CONNECTED; 
}

void EmailChecker::socketConnected()
{   
    qDebug() << "MODE:" << socket.mode();
    if(ssl == 0)
	state = CONNECTED;
}

void EmailChecker::setInfo(QString server_, int port_ ,QString protocol_, int ssl_, QString login_, QString password_)
{
    //reset currentEmails on change server
    if(server.compare(server_))
	currentEmails = -1;
    server = server_;  
    port = port_;
    if(!protocol_.compare("IMAP"))
	protocol = IMAP;
    else
	protocol = POP3;
    ssl = ssl_;
    login = login_;
    password = password_;
}

/* send message */
void EmailChecker::sendMessage(CommandType type)
{
    QString buffer;    
    if (login.isEmpty()){	
	closeConnection();
	updateText("Configure me please!");	
	return;
    }
    switch(type){
	case LOGIN:
	    if(protocol == POP3)
		buffer = "USER "+ login + "\n";
	    else if(protocol == IMAP)
		buffer = ". login "+ login + " " + password + "\n";
	    state = VERIFY_USER;
	    break;
	case PASSWORD:
	    buffer = "PASS " + password + "\n";
	    state = VERIFY_PASSWORD;
	    break;
	case STAT:
	    if(protocol == POP3)
		buffer = "STAT\n";	    
	    else if(protocol == IMAP)
		buffer = ". STATUS INBOX (UNSEEN)\r\n";
	    state = CMD_STAT;	    
	    break;
	default:
	    break;
    }
    qDebug() << "Buffer out:" << buffer;
    socket.write(buffer.toUtf8());
}

/* read data from socket */ 
void EmailChecker::getMessage()
{
    QByteArray buffer;
    buffer = socket.readAll();
    qDebug() << "BUFFER:"  << buffer;    
    if(buffer.contains("OK")){
	switch(state){
	    case CONNECTED:
		qDebug() << "Protocol OK: connected";
		sendMessage(LOGIN);		
		break;
	    case NO_CONNECTED:
		qDebug() << "Code error";
		break;
	    case VERIFY_USER:
		qDebug() << "Verify user: user accepted";
		if(protocol == POP3)
		    sendMessage(PASSWORD);
		else if(protocol == IMAP)
		    sendMessage(STAT);
		break;
	    case VERIFY_PASSWORD:
		qDebug() << "Verify password: password accepted";
		sendMessage(STAT);
		break;
	    case CMD_STAT:
		qDebug() << "Command Stat";
		bool ok;
		QString emailsText;
		int emails;
		if(protocol == POP3){
		    QStringList temp1 = QString(buffer).split(" ");
		    emailsText = temp1.at(1);
		    emails = temp1.at(1).toInt(&ok,10);
		} else if(protocol == IMAP){
		    if(!buffer.contains("UNSEEN")){
			updateText("Not supported");
			closeConnection();
			break;
		    }
		    QStringList temp = QString(buffer).split(" ");
		    QStringList temp2 = QString(temp[4]).split(")");
		    emailsText = QString(temp2[0]);
		    emails = emailsText.toInt(&ok,10);
		}
		if((currentEmails !=-1) && (emails > currentEmails))
		    emit emailReceived(currentEmails);
		currentEmails = emails;
		updateText("You have " +  emailsText + " new messages");		
		closeConnection();
		break;
	}
    } else if (buffer.contains("-ERR") || buffer.contains(". NO") || buffer.contains(". BAD")){ //FIXME
	QString text;
	switch(state){
	     case NO_CONNECTED:
		qDebug() << "Code error";
		break;
	    case CONNECTED:
	    case CMD_STAT:
		qDebug() << "Protocol Error";
		text = "Protocol issues";		
		break;		
	    case VERIFY_USER:
		qDebug() << "Verify user: user NOT accept";
		text = "Wrong user";
		break;
	    case VERIFY_PASSWORD:
		qDebug() << "Verify password: password NOT accepted";
		text = "Authentication failed";
		break;   
	}	
	closeConnection();
	updateText(text);
    }	
}

void EmailChecker::updateText(QString text)
{
    qDebug() << text;
    emit updatedText(text);    
}

void EmailChecker::errorConnection(QAbstractSocket::SocketError error)
 {
     qDebug() << "Error" << error;     
     updateText("Connection Error");
     closeConnection();   
 }
 